package game.display;

import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.util.Iterator;

import javax.swing.JPanel;

import game.MainController;
import com.googlecode.cqengine.resultset.ResultSet;

import game.Engine.GameEngine;
import game.Engine.Entity.Creature;
import game.Engine.Entity.Entity;
import game.Engine.Entity.Player;
import game.menu.Menu;

/** Displays the different images inputted into the game
 * 
 * @author DMEComputer
 *
 */

public class DisplayEngine extends JPanel 
{
	
	/** Creates a viewing window
	 * 
	 * @author DMEComputer
	 *
	 */
	
   public class ViewingWindow 
   {
      private Rectangle2D.Double screen;
      private int lowerBound;
      private int leftBound;
      private int rightBound;
      private Entity centerOn;
      private DisplayEngine de;

      /** Constructs the viewing window
       * 
       * @param de the display engine
       * @param lowerBound the lower bound of the viewing window
       * @param rightBound the right bound of the viewing window
       */
      
      public ViewingWindow(DisplayEngine de, int lowerBound, int rightBound) 
      {
         screen = new Rectangle2D.Double(0, 0, de.getWidth(), de.getHeight());
         this.lowerBound = lowerBound - 64;
         this.rightBound = rightBound - 64;
         this.de = de;
         adjustedBoundingBox = new Rectangle();
      }

      /** Entity is set as the center
       * 
       * @param e the entity is the center
       */
      
      public void setCenteredOn(Entity e) 
      {
         centerOn = e;
      }

      /** Sets the screen width and height equal to the
       * display mode width and height
       * 
       */
      
      public void centeronE() 
      {
         screen.width = de.getWidth();
         screen.height = de.getHeight();
         centerOn(centerOn);
      }

      /** Makes sure the player is always in the center of the screen
       * 
       * @param e the entity is the center
       */
      
      public void centerOn(Entity e) 
      {
         double adjustedX = (int) ((e.getX() + 1) * 64 - screen.width / 2.0);
         double adjustedY = (int) ((e.getY()) * 64 - screen.height / 2.0);
         if (adjustedX < leftBound) 
         {
            adjustedX = leftBound;
         }
         if (adjustedX + screen.width > rightBound) 
         {
            adjustedX = rightBound - screen.width;
         }
         if (adjustedY + screen.height > lowerBound) 
         {
            adjustedY = lowerBound - screen.height;
         }
         screen.x = adjustedX;
         screen.y = adjustedY;
      }

      private Rectangle adjustedBoundingBox;

      /** Returns how much of the entity is seen
       * 
       * @param e the entity
       * @return how much of the entity is seen
       */
      
      public boolean seen(Entity e) 
      {
         adjustedBoundingBox.setBounds((int) (e.getBoundingBox().getX() * 64),
               ((int) e.getBoundingBox().getY() * 64), (int) (e
                     .getBoundingBox().getWidth() * 64), (int) (e
                     .getBoundingBox().getHeight() * 64));
         return adjustedBoundingBox.intersects(screen);
      }

      /** Returns the screen starting x-coordinate
       * 
       * @return the screen starting x-coordinate
       */
      
      public int getX() 
      {
         return (int) screen.getX();
      }

      /** Returns the screen starting y-coordinate
       * 
       * @return the screen starting y-coordinate
       */
      
      public int getY() 
      {
         return (int) screen.getY();
      }

      /** Returns the screen width
       * 
       * @return the screen width
       */
      
      public int getW() 
      {
         return (int) screen.getWidth();
      }

      /** Returns the screen height
       * 
       * @return the screen height
       */
      
      public int getH() 
      {
         return (int) screen.getHeight();
      }
   }

   private GameEngine ge;
   private Menu me;
   public ViewingWindow vw;
   private OverlayImage oi;
   private Background b;

   /** Constructs the display window
    * 
    * @param g the graphics
    */
   
   public void displayGame(GameEngine g) 
   {
      this.ge = g;
      vw = new ViewingWindow(this, ge.getMaxY() * 64, ge.getMaxX() * 64);
      vw.setCenteredOn(ge.player);
      vw.centeronE();
      oi = new OverlayImage();
      b = new Background(getWidth(),getHeight(), 2, 3);
      MainController.setState(MainController.State.GAME);
   }

   /** Constructs a main menu
    * 
    * @param m the menu
    */
   
   public void displayMenu(Menu m) 
   {
      this.me = m;
   }

   /** Based on what the user chooses in the main menu
    * either the game, menu, tutorial menu, high score menu, 
    * or null is drawn
    * 
    */
   
   public void paintComponent(Graphics g) 
   {
      switch (MainController.getState()) 
      {
      case GAME:
         drawGame(g);
         break;
      case MENU:
         drawMenu(g);
         break;
      case TUTORIAL_MENU:
    	  drawMenu(g);
    	  break;
      case HIGHSCORE_MENU:
    	  drawMenu(g);
    	  break;
      case NULL:
         break;
      }
   }

   /** Draws the viewing window, background, and other things that are displayed
    * 
    * @param g the graphics
    */
   
   public void drawGame(Graphics g) 
   {
      vw.centeronE();
      ResultSet<Entity> e = ge.runQuery(
            MainController.gameEngine.all,
            Entity.ENTITY_Z);
      b.draw(g);
      //g.drawImage(Images.BACKGROUND.staticImage().getImage(), 0, 0, null);
      for (Iterator<Entity> i = e.iterator(); i.hasNext();) 
      {
         Entity f = i.next();
         if (vw.seen(f)) 
         {
            if (f instanceof Creature) 
            {
               Creature c = (Creature) f;
               HealthBar.updateHealthBar(g, c.getX() * 64 - vw.getX(), c.getY()
                     * 64 - vw.getY() - 5, c.getHealth(), c.getMaxHealth());
            }
            g.drawImage(f.getCurrentImage(), (int) (f.getX() * 64) - vw.getX(),
                  (int) (f.getY() * 64) - vw.getY(), null);
         }
      }
      oi.update(g);
      repaint();
   }

   /** Draws the main menu
    * 
    * @param g the graphics
    */
   
   public void drawMenu(Graphics g) 
   {
      if (me != null)
         me.drawMenu(g);
      try 
      {
		Thread.sleep(50);
	} catch (InterruptedException e) 
	{
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
      repaint();
   }
}